﻿using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WpfApp1.Themes
{
    public static class ResourceDictionaryExtensions
    {
        private static ConcurrentDictionary<BaseThemeType, BaseTheme> themeDict = new ConcurrentDictionary<BaseThemeType, BaseTheme>();

        /// <summary>
        /// 切换颜色
        /// </summary>
        /// <param name="resourceDictionary"></param>
        /// <param name="themeType"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static BaseTheme SetTheme(this ResourceDictionary resourceDictionary, BaseThemeType themeType)
        {
            if (resourceDictionary is null) throw new ArgumentNullException(nameof(resourceDictionary));


            BaseTheme theme = new BaseTheme();
            if (themeDict.TryGetValue(themeType, out var valuePairs))
            {
                theme = valuePairs;
                Type type = typeof(BaseTheme);
                var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var property in properties)
                {
                    var color = resourceDictionary[property.Name];
                    if (color == null)
                    {
                        continue;
                    }
                    //颜色格式约束：结尾是Color的替换为Brush,否则直接添加Brush后缀
                    var bushName = property.Name.EndsWith("Color") ? property.Name.Replace("Color", "Brush") : (property.Name + "Brush");
                    SetSolidColorBrush(resourceDictionary, bushName, color.ToString());
                }
            }
            else
            {
                Type type = typeof(BaseTheme);
                var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var property in properties)
                {
                    var color = resourceDictionary[property.Name];
                    if (color == null)
                    {
                        continue;
                    }
                    property.SetValue(theme, color);
                    //颜色格式约束：结尾是Color的替换为Brush,否则直接添加Brush后缀
                    var bushName = property.Name.EndsWith("Color") ? property.Name.Replace("Color", "Brush") : (property.Name + "Brush");
                    SetSolidColorBrush(resourceDictionary, bushName, color.ToString());
                }
                theme.ThemeType = themeType;
                themeDict.TryAdd(themeType, theme);
            } 
            return theme;
        }

        private static void SetSolidColorBrush(this ResourceDictionary sourceDictionary, string name, string color)
        {
            if (sourceDictionary is null) throw new ArgumentNullException(nameof(sourceDictionary));
            if (name is null) throw new ArgumentNullException(nameof(name));


            if (sourceDictionary[name] is SolidColorBrush brush)
            {
                if (brush.Color.ToString() == color) { return; }
                if (!brush.IsFrozen)
                {
                    var animation = new ColorAnimation
                    {
                        From = brush.Color,
                        To = (Color)ColorConverter.ConvertFromString(color),
                        Duration = new Duration(TimeSpan.FromMilliseconds(300))
                    };
                    brush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
                    return;
                }
            }

            var newBrush = (Brush)(new BrushConverter()).ConvertFromString(color);
            newBrush.Freeze();
            sourceDictionary[name] = newBrush;
        }

        private static void SetLinearGradientBrush(this ResourceDictionary sourceDictionary, string name, Color value, Color value2)
        {
            if (sourceDictionary is null) throw new ArgumentNullException(nameof(sourceDictionary));
            if (name is null) throw new ArgumentNullException(nameof(name));


            var newBrush = new LinearGradientBrush();
            newBrush.StartPoint = new Point(1, 0.5);
            newBrush.EndPoint = new Point(0, 0.5);

            var stops = new GradientStopCollection();
            stops.Add(new GradientStop() { Color = value, Offset = 1 });
            stops.Add(new GradientStop() { Color = value2, Offset = 0 });
            newBrush.GradientStops = stops;

            newBrush.Freeze();
            sourceDictionary[name] = newBrush;
        }
    }
}
